package view;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.rmi.RemoteException;

import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

import controller.FirewallSession;
import server.FirewallException;
import server.ReadWriteException;
import server.RulesTableType;

/**
 * Class is responsible for rules frame.
 * Frame contains: 	two tables - for rules with IN and OUT directions.
 * 					Help and Finish buttons.
 * 					Ruleset operation buttons (load, new, delete, set as active).
 * 					Other buttons depend on inheriting class.
 */
public abstract class AbstractRulesFrame extends JFrame
{
	/**
	 * Server controller
	 */
	protected FirewallSession UI;
	
	/**
	 * Current shown rules frame
	 */	
	public static AbstractRulesFrame currentRulesFrame = null;
	

	/**
	 * C'tor - Frame with specified controller is created:
	 * two tables, action buttons and stadart buttons are defined. 
	 * @param ui	- the controller for the system actions
	 */
	public AbstractRulesFrame(FirewallSession ui)
	{	
		super("Rules");
		UI = ui;
		try
		{
			/* Default ruleset is the current ruleset */
			Settings.ruleset = UI.getCurrentRuleSet();
			
			setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
			setSize(Globals.rulesFrameSize);
			setLayout(new BorderLayout());
			
			/*Standart buttons for the frame*/
			JPanel b = new JPanel(new GridLayout(1,2));
			addStandartButtons();
			
			Box upButtons = getUpRulesButtons();
			b.add(upButtons);
			
			Box downButtons = getDownRulesButtons();
			if((upButtons != null) && (downButtons!= null))
			{
				b.add(downButtons);
			}
			add(b, BorderLayout.NORTH);
			
			/* Tables for the frame */
			JPanel tables = getRulesTables();
			if(tables != null)
			{
				add(tables, BorderLayout.CENTER);
			}
		} catch (RemoteException e) {
			ErrorFrame.AddError("Can't create rules table frame :"+ e.getMessage(), this);
		}
		
		setLocationRelativeTo(null);
	}

	/**
	 * The relevant help calling
	 */
	protected void rulesHelp()
	{
		HelpFrame.currentHelpFrame.ShowDesc(Globals.RULES);	
	}

	/**
	 * This method adds standart finish/help buttons to the current frame
	 */
	private void addStandartButtons()
	{
		Box tableBox = Box.createHorizontalBox();
		
		JButton finish = new JButton("Finish");
		finish.setToolTipText("Close and save changes");
		JButton help = new JButton("Help");
		help.setToolTipText("Help for rules screen");
		
		tableBox.add(help);		
		tableBox.add(finish);
		
		/*Help button listener - open the relevant help */		
		help.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) 
			{
				rulesHelp();
			}	  
		});
		
		/*Finish button listener - closes the frame*/		
		finish.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) 
			{
				dispose();				
			}	  
		});

	    add(tableBox, BorderLayout.SOUTH);
	}

	/**
	 * Adds the two rules tables
	 */
	protected JPanel getRulesTables()
	{
		/* Types of tables to create */
		RulesTableType[] tableChoice = {RulesTableType.IN, RulesTableType.OUT}; 
		String[] tableLocation = {BorderLayout.NORTH, BorderLayout.SOUTH}; 
		
		/* Common panel */
		JPanel tables = new JPanel(new BorderLayout());
		
		for(int i = 0; i < tableChoice.length; i++)
		{
			/* Panel for rules */
			JPanel table = new JPanel(new BorderLayout());
			
			/* Table */
			AbstractRulesTable rules = getTable(tableChoice[i]);
			
			/* Label adding */
			JLabel label = new JLabel(rules.getType() + " rules:");
			table.add(label, BorderLayout.NORTH);
			
			/* Header adding */
			table.add(rules.getRulesTableHeader(), BorderLayout.CENTER);
			rules.getTableHeader().setReorderingAllowed(false);	
			
			/* Table adding */
			JScrollPane scrollpane = new JScrollPane(rules);
			scrollpane.getViewport().setPreferredSize(new Dimension(200,195));
			table.add(scrollpane,  BorderLayout.SOUTH);
			
			tables.add(table, tableLocation[i]);
		}

		return tables;
	}
	
	/**
	 * Adds buttons for ruleset loading, saving and reseting
	 */
	protected Box getUpRulesButtons() 
	{
		/* Button for loading */	
		Box buttons = Box.createVerticalBox();
		
		/* Button for new ruleset openning */		
		JButton newRuleset = new JButton("New ruleset");
		newRuleset.setMaximumSize(Globals.buttonSize);
		newRuleset.setToolTipText("Save the displayed ruleset");
		
		newRuleset.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) 
			{
				RulesetNewFrame frame = new RulesetNewFrame(UI);
				frame.setVisible(true);
			}	  
		});
		
		/* New ruleset button defined only for advanced user */
		if(Settings.userMode.equals(UserMode.ADVANCED))
		{
			buttons.add(newRuleset);
		}
				
		JButton load = new JButton("Load ruleset");
		load.setMaximumSize(Globals.buttonSize);
		load.setToolTipText("Load the ruleset by user choice");
		
		load.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) 
			{
				RulesetLoadFrame frame = new RulesetLoadFrame(UI);
				frame.setVisible(true);
			}	  
		});
		buttons.add(load);
	
		/* Button for deleting ruleset */	
		JButton delete = new JButton("Delete ruleset");
		delete.setToolTipText("Delete the ruleset by user choice");
		delete.setMaximumSize(Globals.buttonSize);
		delete.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) 
			{
				RulesetDeleteFrame frame = new RulesetDeleteFrame(UI);
				frame.setVisible(true);
			}	  
		});
		
		/* Delete button defined only for advanced user */
		if(Settings.userMode.equals(UserMode.ADVANCED))
		{
			buttons.add(delete);
		}
		
		/* Button for reseting */	
		JButton reset = new JButton("Active ruleset");
		reset.setToolTipText("Load active Firewall's ruleset ");
		reset.setMaximumSize(Globals.buttonSize);
		
		buttons.add(reset);
		reset.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) 
			{
				try {
					Settings.ruleset = UI.getCurrentRuleSet();
					/* Build the appropriate table */
					switch(Settings.userMode)
					{
					case STANDART:
						RulesStandartTable.currentInRulesTable.build();
						RulesStandartTable.currentOutRulesTable.build();
						RulesStandartFrame.currentRulesFrame.isCurrentRuleSet(true);
						break;
						
					case ADVANCED:
						Settings.ruleset = UI.getCurrentRuleSet();
						RulesAdvancedTable.currentInRulesTable.build();
						RulesAdvancedTable.currentOutRulesTable.build();
						RulesAdvancedFrame.currentRulesFrame.isCurrentRuleSet(true);
						break;
					}
				} catch (RemoteException e1) {
					ErrorFrame.AddError("Failed to reset ruleset :" + e1.getMessage(), new JFrame());
				}
			}	  
		});
		

		/* Button for reseting */	
		JButton set = new JButton("Set as active");
		set.setToolTipText("Set displayed ruleset to be active ruleset at firewall");
		set.setMaximumSize(Globals.buttonSize);
		set.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) 
			{
				try {
					UI.setRuleSet(Settings.ruleset);
					isCurrentRuleSet(true);
				} catch (RemoteException e1) {
					ErrorFrame.AddError("Failed to set this ruleset as current:" + e1.getMessage(), new JFrame());
				} catch (FirewallException e1) {
					ErrorFrame.AddError("Failed to set this ruleset as current:"+ e1.getMessage(), new JFrame());
				} catch (ReadWriteException e1) {
					ErrorFrame.AddError("Failed to set this ruleset as current:"+ e1.getMessage(), new JFrame());
				}
				
			}	  
		});

		buttons.add(set);
		
		
		return buttons;	
	}
	
	/**
	 * Action on changing the table. Table displays current/not current FW ruleset.
	 * @param flag if the ruleset is current
	 */
	public void isCurrentRuleSet(boolean isCurrent)
	{
		if (isCurrent ){
			setTitle(getTitle());
		}
		else{
			setTitle(getTitle() + " : ruleset " + Settings.ruleset);
		}
	}

	/**
	 * @param table in/out type
	 * @return table of rules
	 */
	protected abstract AbstractRulesTable getTable(RulesTableType type);
	
	protected abstract Box getDownRulesButtons();
}
